package ex;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @Description 差集偶类
 * @Date 2022/3/19 17:49
 * @Author eric ling
 */
public class DiffSetPair {
    private int v; // 有限群的阶
    private int k1; // 集合D1的元素个数
    private int k2; // 集合D2的元素个数
    private int e; // 集合D1和集合D2的交集的元素个数
    private int lambda; // 有限群非零元在差表D2-D1中的出现次数
    private int[] vSet; // 有限群（循环的）
    private int[] k1Set; // 集合D1
    private int[] k2Set; // 集合D2
    private int[] eSet; // 集合D1和集合D2的交集

    public DiffSetPair(int v, int k1, int k2, int e) {
        this.v = v;
        this.k1 = k1;
        this.k2 = k2;
        this.e = e;
        // 计算lambda对应的值，需满足条件 K1*k2=lambda*(v-1)+e
        this.lambda = ((k1 * k2) - e) / (v - 1);
        int[] vSet = new int[v];
        for (int i = 0; i < v; i++) {
            vSet[i] = i;
        }
        this.vSet = vSet;
    }

    public DiffSetPair(int v, int k1, int k2, int e, int lambda) {
        this.v = v;
        this.k1 = k1;
        this.k2 = k2;
        this.e = e;
        this.lambda = lambda;
        int[] vSet = new int[v];
        for (int i = 0; i < v; i++) {
            vSet[i] = i;
        }
        this.vSet = vSet;
    }

    public DiffSetPair(int[] nums) {
        this.v = nums[0];
        this.k1 = nums[1];
        this.k2 = nums[2];
        this.e = nums[3];
        this.lambda = nums[4];
        int[] vSet = new int[v];
        for (int i = 0; i < v; i++) {
            vSet[i] = i;
        }
        this.vSet = vSet;
    }

    public int getV() {
        return v;
    }

    public void setV(int v) {
        this.v = v;
    }

    public int getK1() {
        return k1;
    }

    public void setK1(int k1) {
        this.k1 = k1;
    }

    public int getK2() {
        return k2;
    }

    public void setK2(int k2) {
        this.k2 = k2;
    }

    public int getE() {
        return e;
    }

    public void setE(int e) {
        this.e = e;
    }

    public int getLambda() {
        return lambda;
    }

    public void setLambda(int lambda) {
        this.lambda = lambda;
    }

    public int[] getvSet() {
        return vSet;
    }

    public void setvSet(int[] vSet) {
        this.vSet = vSet;
    }

    public int[] getK1Set() {
        return k1Set;
    }

    public void setK1Set(int[] k1Set) {
        Arrays.sort(k1Set);
        this.k1Set = k1Set;
    }

    public int[] getK2Set() {
        return k2Set;
    }

    public void setK2Set(int[] k2Set) {
        Arrays.sort(k2Set);
        this.k2Set = k2Set;
    }

    public int[] geteSet() {
        return eSet;
    }

    public void seteSet(int[] eSet) {
        Arrays.sort(eSet);
        this.eSet = eSet;
    }

    @Override
    public String toString() {
        Objects.requireNonNull(k1Set, "k1Set不可为空");
        Objects.requireNonNull(k2Set, "k2Set不可为空");

        return "ex.DiffSetPair{" + "v=" + v + ", k1=" + k1 + ", k2=" + k2 + ", e=" + e + ", lambda=" + lambda + ", k1Set=" + Arrays.toString(k1Set) + ", k2Set=" + Arrays.toString(k2Set) + ", eSet=" + Arrays.toString(eSet) + '}';
    }

    /**
     * @return 此差集偶对应的二元序列偶 Binary Sequence Pairs
     */
    public BinSeqPairs getBinSeqPairs() {
        Objects.requireNonNull(k1Set, "k1Set不可为空");
        Objects.requireNonNull(k2Set, "k2Set不可为空");

        int[] x = new int[v];
        int[] y = new int[v];
        Arrays.fill(x, -1);
        Arrays.fill(y, -1);
        // 遍历集合d1，构造对应的特征序列
        for (int i : this.k1Set) {
            x[i] = 1;
        }

        // 遍历集合d2，构造对应的特征序列
        for (int i : this.k2Set) {
            y[i] = 1;
        }
        return new BinSeqPairs(v, x, y);
    }


//    public boolean isDiffSetPair() {
//        ex.BinSeqPairs pairs = getBinSeqPairs();
//        long[] correlation = pairs.correlation();
//        boolean isBinomial = Arrays.stream(correlation).distinct().count() == 2;
//        // 差集偶对应的特征序列偶都是二值自相关二元序列偶，二值自相关二元序列偶对应的特征集满足一定条件才是差集偶
//        // 这个条件即为：R=v-2(k1+k2)+4e step=0,R=v-2(k1+k2)+4lambda step!=0 R为自相关函数值
//        return isValid() && isBinomial && correlation[0] == (v - 2L * (k1 + k2) + 4L * e) && correlation[1] == (v - 2L * (k1 + k2) + 4L * lambda);
//    }

    /**
     * 根据定义判断当前(U,V) 是否构成指定参数的DSP(v,k1,k2,e,lambda)
     *
     * @return 当前组合是否为差集偶
     */
    public boolean isDiffSetPair() {
        // if(!isValid()) return false;
        Objects.requireNonNull(k1Set, "k1Set不可为空");
        Objects.requireNonNull(k2Set, "k2Set不可为空");

        // 构造差表
        int[] occurrence = new int[v];
        for (int i : k1Set) {
            for (int j : k2Set) {
                occurrence[(i - j + v) % v]++;
            }
        }
        for (int i = 1; i < occurrence.length; i++) {
            if (occurrence[i] != lambda) return false;
        }
        return true;
    }

    public static boolean isDiffSetPair(int v, int[] k1set, int[] k2set) {
        // 找出e
        HashSet<Integer> s1 = Arrays.stream(k1set).boxed().collect(Collectors.toCollection(HashSet::new));
        HashSet<Integer> s2 = Arrays.stream(k2set).boxed().collect(Collectors.toCollection(HashSet::new));
        s1.retainAll(s2);
        int k1 = k1set.length;
        int k2 = k2set.length;
        int e = s1.size();
        int lambda = ((k1 * k2) - e) / (v - 1);
        // 构造差表
        int[] occurrence = new int[v];
        for (int i : k1set) {
            for (int j : k2set) {
                occurrence[(i - j + v) % v]++;
            }
        }
        for (int i = 1; i < occurrence.length; i++) {
            if (occurrence[i] != lambda) return false;
        }
        return true;
    }

    /**
     * 预筛选不合理的参数
     *
     * @param v      有限群的阶
     * @param k1     集合D1的元素个数
     * @param k2     集合D2的元素个数
     * @param e      集合D1和集合D2的交集的元素个数
     * @param lambda 有限群非零元在差表D2-D1中的出现次数
     * @return 判断给定的系统变量参数是否可以构成一个差集偶（仅仅是利用必要条件筛除，并非充要条件）
     */
    public static boolean isValid(int v, int k1, int k2, int e, int lambda) {
        return k1 * k2 == lambda * (v - 1) + e;
    }

    public static boolean isValid(int[] nums) {
        return nums[1] * nums[2] == nums[4] * (nums[0] - 1) + nums[3];
    }

    public boolean isValid() {
        return k1 * k2 == lambda * (v - 1) + e;
    }

    public static void main(String[] args) {
        // DSP(13,6,6,0,3) D1={1,3,9,4,12,10} D2={2,6,5,7,8,11}
//        DiffSetPair p = new DiffSetPair(13, 6, 6, 0, 3);
        int[] x1 = {1, 3, 9, 4, 12, 10};
        int[] y1 = {2, 6, 5, 7, 8, 11};
//        p.setK1Set(x1);
//        p.setK2Set(y1);
//        System.out.println(p);
//        System.out.println("是否为差集偶：" + p.isDiffSetPair());
//        System.out.println("对应的二元序列偶：" + p.getBinSeqPairs());
//        System.out.println("对应二元序列偶的自相关函数值：" + Arrays.toString(p.getBinSeqPairs().correlation()));
        System.out.println(isDiffSetPair(13, x1, y1));
        // D1：4,4,12,36,8,20,24,0,5,41,45,13,15,19,31,39,14,22,42,2,6,18,26
        // D2：4,12,36,8,20,24,5,41,45,13,15,19,31,39,26
        int[] d1 = {4, 4, 12, 36, 8, 20, 24, 0, 5, 41, 45, 13, 15, 19, 31, 39, 14, 22, 42, 2, 6, 18, 26};
        int[] d2 = {4, 12, 36, 8, 20, 24, 5, 41, 45, 13, 15, 19, 31, 39, 26};
        System.out.println(isDiffSetPair(68, d1, d2));

        System.out.println(new DiffSetPair(19, 14, 15, 12).getLambda());
    }
}
